/*
 * http_conn.h
 *
 *  Created on: 2015-5-15
 *      Author: likui
 */

#ifndef HTTP_CONN_H_
#define HTTP_CONN_H_

#include <stdbool.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/socket.h>

#define DOC_ROOT	"."
#define FILENAME_LEN	20
#define READ_BUFFER_SIZE	4096
#define WRITE_BUFFER_SIZE	4096

typedef enum CHECK_STATE {
	CHECK_STATE_REQUESTLINE = 1,		// 下一步读取请求行
	CHECK_STATE_HEADER = 2,			// 下一步读取首部
	CHECK_STATE_CONTENT = 3			// 下一步读取正文
}CHECK_STATE;

typedef enum LINE_STATE {
	LINE_OK = 1,			// 行数据读取成功
	LINE_BAD = 2,			// 行数据读取出错
	LINE_OPEN = 3			// 行数据读取不完整
} LINE_STATE;

typedef enum METHOD {
	GET = 1,				// 从服务器获取一份文档
	HEAD = 2,				// 只从服务器获取文档的首部
	POST = 3,				// 向服务器发送需要处理的数据
	PUT = 4,				// 将请求的主体部分存储在服务器上
	TRACE = 5,				// 对可能经过代理服务器传送到服务器上去的报文进行追踪
	OPTTIONS = 6,			// 决定可以在服务器上执行哪些方法
	DELETE = 7				// 从服务器上删除一份文档
} METHOD;

typedef enum HTTP_CODE {
	INTERNAL_ERROR = 1,
	NO_REQUEST = 2,			// 无响应
	FILE_REQUEST = 3,
	CLOSED_CONNECTION = 4,
	GET_REQUEST = 5,			// 生成响应

	BAD_REQUEST = 400,
	FORBIDDEN = 403,
	NOT_FOUND = 404,
	NOT_IMPLEMENTED = 500,
	HTTP_VERSION_NOT_SUPPORTED = 505
} HTTP_CODE;

typedef struct string {
	size_t	len;		// 长度
	char	*data;		// 数据
}string_t;

#define STRING(str) { sizeof(str) - 1, (char *)str }

typedef struct http_status_t {
	int			status;			// 错误代码
	string_t	reason;			// 原因短语
	string_t	content;		// 正文
}http_status_t;

typedef struct tw_timer_t tw_timer_t;

typedef struct http_conn_t {

	// HTTP连接的套接字
	int		sockfd;

	// 对方的套接字地址
	struct sockaddr		peer_address;
	socklen_t				peer_addrlen;

	// 读
	char	read_buf[READ_BUFFER_SIZE];		// 读缓冲区
	int		rd_read_index;						// 已读入的最后一个字节的下一个位置
	int		rd_check_index;					// 正在分析的字符在缓冲区的位置
	int		rd_start_line;					 	// 行的起始位置

	// 写
	char	write_buf[WRITE_BUFFER_SIZE];	// 写缓冲区
	int		wr_length;							// 缓冲区中待发送的字节数

	CHECK_STATE check_state;					// 分析状态机所处状态

	// HTTP协议信息
	METHOD	http_method;						// 方法
	char	*http_url;							// URL
	char	*http_version;						// 版本号
	char	*http_host;						// 主机名
	int		http_content_len;					// 正文长度
	bool	http_linger;						// 保持连接
	char	*http_file_address;				// 客户请求的目标文件被mmap到内存的起始位置

	// 文集信息
	char		http_filename[FILENAME_LEN];		// 客户请求的目标文件
	struct stat http_file_stat;					// 文件信息

	struct iovec	http_iov[2];
	int				http_iov_count;

	// 定时器
    tw_timer_t    *timer;

} http_conn_t;

void set_fl(int fd, int flags);
void epoll_add(int epollfd, int fd, bool one_shot);
void epoll_rm(int epollfd, int fd);
void epoll_mod(int epollfd, int fd, int ev);

void http_conn_close_conn(http_conn_t *http_conn, bool real_close, int epollfd);
void http_conn_init_part(http_conn_t *http_conn);
void http_conn_init(http_conn_t *http_conn,int sockfd, const struct sockaddr *addr, socklen_t addrlen, int epollfd);
char * http_conn_get_line(http_conn_t *http_conn);
bool http_conn_read(http_conn_t *http_conn);
LINE_STATE http_conn_parse_line(http_conn_t *http_conn);
HTTP_CODE http_conn_parse_request_line(http_conn_t *http_conn, char *text);
HTTP_CODE http_conn_parse_headers(http_conn_t *http_conn, char *text);
HTTP_CODE http_conn_process_content(http_conn_t *http_conn, char *text);
HTTP_CODE http_conn_process_read(http_conn_t *http_conn);
HTTP_CODE http_conn_do_request(http_conn_t *http_conn);
void http_conn_unmap(http_conn_t *http_conn);
bool http_conn_write(http_conn_t *http_conn, int epollfd);
bool http_conn_add_response(http_conn_t *http_conn, const char *format, ... );
bool http_conn_add_status_line(http_conn_t *http_conn, int status, const char *title);
bool http_conn_add_headers(http_conn_t *http_conn, int content_len);
bool http_conn_add_content_length(http_conn_t *http_conn, int content_len);
bool http_conn_add_linger(http_conn_t *http_conn);
bool http_conn_add_blank_line(http_conn_t *http_conn);
bool http_conn_add_content(http_conn_t *http_conn, const char *content);
bool http_conn_process_write(http_conn_t *http_conn, HTTP_CODE ret);
void http_conn_process(http_conn_t *http_conn, int epollfd);

#endif /* HTTP_CONN_H_ */
